home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / which5.zoo / which5.c < prev   
C/C++ Source or Header  |  1992-07-03  |  7KB  |  308 lines

  1. /*
  2.  * which [-i] [-a] [--] [<command>]
  3.  * alias which alias !\$ \| /usr/local/bin/which -i !\*
  4.  * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
  5.  * which()
  6.  * {
  7.  *    eval last=\"\$$#\"
  8.  *    set | sed -n "/^$last(){$/,/^}$/p" |
  9.  *        /usr/local/bin/which -i ${1+"$@"}
  10.  * }
  11.  *
  12.  * Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
  13.  * First change:
  14.  *    Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
  15.  *    the access() system call considering everything executable for
  16.  *    root (!), so we give root a special treatment.  :-(
  17.  *    `which', `which -i' and `which -a' with no further arguments now
  18.  *    return the PATH environment variable, split up into its components.
  19.  *    The aliases defined above are slightly different from the previous
  20.  *    version - now it's the shell who's doing the alias checking.
  21.  * Second change:
  22.  *    Added support for shell functions and multiline aliases, added the
  23.  *    `--' option, changed the source style.
  24.  * Third change:
  25.  *    To hell with access()!
  26.  *    Now stat() is used to give the right answer even if the effective
  27.  *    uid (gid) differs from the real uid (gid).
  28.  *    We can't use setuid(geteuid()), because that's nonportable.  :-(
  29.  * Fourth change:
  30.  *    Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
  31.  *    the stack if the PATH is longer than BUF_SIZE - 1 characters.
  32.  *    I've changed convert() altogether to return a path vector (cf. argv),
  33.  *    whose components are the respective directories in the PATH.
  34.  *    Furthermore in printing the PATH there are no trailing colons anymore.
  35.  */
  36.  
  37. #include    <sys/types.h>
  38. #include    <sys/stat.h>
  39. #include    <stdio.h>
  40. #ifdef __GNUC__
  41. /* for all the extern progs... */
  42. #include <stdlib.h>
  43. #include <unistd.h>
  44. #include <string.h>
  45. #endif
  46.  
  47. #if defined(__GNUC__) && defined(atarist)
  48. /* note: tcsh keeps PATH like .:/dev/c/bin:... but when it sets up an env
  49.    for a prog, it converts it to .,c:\bin,... */    
  50. #define DIRSEP    ','
  51. #define SLASH    '\\'
  52. #else
  53. #define DIRSEP    ':'
  54. #define SLASH    '/'
  55. #endif
  56.  
  57. #define        BUF_SIZE    512
  58. #define        M_USR        0700
  59. #define        M_GRP        0070
  60. #define        M_OTH        0007
  61. #define        X_ALL        0111
  62. #define        R_ALL        0444
  63.  
  64. char    Version[] =
  65.     "@(#)which 5.0 90/03/24 Maarten Litmaath @ VU Informatika Amsterdam";
  66. char    *Prog;
  67.  
  68. #ifdef atarist
  69. /* we need to look for files with extensions, too... */
  70. char *extn[] = {"",     ".ttp", ".prg", ".tos", ".acc",
  71.         ".csh", ".sh",  ".g",   (char *)0};
  72. #endif
  73.  
  74.  
  75. void    usage()
  76. {
  77.     fprintf(stderr, "%s\n\n", Version);
  78.     fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
  79.     exit(1);
  80. }
  81.  
  82. #ifdef __GNUC__
  83. char    **convert();
  84. #endif
  85.  
  86. void main(argc, argv) 
  87. int    argc;
  88. register char    **argv;
  89. {
  90.     register char    *path, *s, **pathv, **p;
  91. #ifdef __GNUC__
  92.     char    buf[BUF_SIZE];
  93. #else
  94.     char    *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
  95. #endif
  96.     int    all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
  97.         xmask, rmask;
  98.     struct    stat    st;
  99.     void    usage();
  100. #ifdef atarist
  101.     /* to deal with extensions... */
  102.     int    stret;
  103.     char   *pend;
  104.     char  **pextn;
  105. #endif
  106.  
  107.  
  108.     Prog = *argv++;
  109.     --argc;
  110.  
  111.     while (!stop && (s = *argv) && (*s == '-')) {
  112.         ++argv;
  113.         --argc;
  114.         ++s;
  115.         while (*s)
  116.             switch (*s++) {
  117.             case 'a':
  118.                 all = 1;
  119.                 break;
  120.             case 'i':
  121.                 inter = 1;
  122.                 break;
  123.             case '-':
  124.                 stop = 1;
  125.                 break;
  126.             default:
  127.                 usage();
  128.             }
  129.     }
  130.  
  131.     if (argc > 1)
  132.         usage();
  133.  
  134.     if (inter && *argv) {
  135.         while (fgets(buf, sizeof buf, stdin)) {
  136.             if (!found) {
  137. /*!!!                printf("%s", *argv);*/
  138.                 printf("%s:", *argv);
  139.                 found = 1;
  140.             }
  141. /*!!!            printf("\t%s", buf);*/
  142.             printf("\taliased to %s", buf);
  143.         }
  144.         if (found && !all)
  145.             exit(0);
  146.     }
  147.  
  148.     if (!(path = getenv("PATH"))) {
  149.         fprintf(stderr, "%s: no PATH in environment!\n", Prog);
  150.         exit(1);
  151.     }
  152.  
  153.     if (!*path)
  154.         path = ".";        /* another dubious convention */
  155.  
  156.     pathv = convert(path);        /* convert path string to vector */
  157.  
  158.     if (!*argv) {            /* print path if no more arguments */
  159.         while (*pathv)
  160.             puts(*pathv++);
  161.         exit(0);
  162.     }
  163.  
  164.     uid = geteuid();
  165.     gid = getegid();
  166.     if (uid == 0) {
  167.         xmask = X_ALL;
  168.         rmask = R_ALL;
  169.     }
  170.  
  171.     for (p = pathv; path = *p++; ) {    /* try every component */
  172.         s = buf;
  173.         while (*s++ = *path++)
  174.             ;
  175.         (void) strcpy(s, *argv);
  176.         *--s = SLASH;
  177.  
  178. #ifdef atarist
  179.         /*
  180.          *   here we deal with extensions. keep a ptr to null at
  181.          *   end of basic string. this assumes user did NOT give
  182.          *   a suffix! then we move along the list until we find
  183.          *   a regular file. if we get thru the loop, and if list
  184.          *   was exhausted, next. otherwise test again if reg file.
  185.          */
  186.         pend = &buf[strlen(buf)];    /* -> null at end */
  187.         for (pextn = extn; *pextn; pextn++)
  188.         {
  189.             strcpy (pend, *pextn);
  190. /*fprintf(stderr,"test %s\n",buf);*/
  191.             if (stret = stat(buf, &st) == 0
  192.             && (st.st_mode & S_IFMT) == S_IFREG)
  193.                 break;
  194.         }
  195.         if (*pextn == NULL)
  196.             continue;
  197.         if (stret == 0 && (st.st_mode & S_IFMT) != S_IFREG)
  198.             continue;
  199. #else
  200.         if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
  201.             continue;
  202. #endif
  203.  
  204.         /* file exists and is regular */
  205.  
  206.         if (uid != 0) {
  207.             mask = st.st_uid == uid ? M_USR :
  208.                 st.st_gid == gid ? M_GRP : M_OTH;
  209.             xmask = X_ALL & mask;
  210.             rmask = R_ALL & mask;
  211.         }
  212.  
  213.         if (!(st.st_mode & xmask))
  214.             continue;
  215.  
  216.         /* file is executable */
  217.  
  218.         *s = 0;
  219.         if (stat(buf, &st) != 0) {
  220.             perror(buf);
  221.             continue;
  222.         }
  223.  
  224.         if (!(st.st_mode & rmask)) {
  225.             fprintf(stderr,
  226.                 "%s: %s found in unreadable directory %s!\n",
  227.                 Prog, *argv, buf);
  228.             found = 1;
  229.             continue;
  230.         }
  231.  
  232.         /* directory is readable */
  233.  
  234.         *s = SLASH;
  235.         puts(buf);
  236.         if (!all)
  237.             exit(0);
  238.         found = 1;
  239.     }
  240.  
  241.     if (found)
  242.         exit(0);
  243.  
  244.     fprintf(stderr, "%s not found in:\n", *argv);
  245.     while (*pathv)
  246.         fprintf(stderr, "%s\n", *pathv++);
  247.     exit(1);
  248. }
  249.  
  250.  
  251.  
  252. char    **convert(path)
  253. char    *path;
  254. {
  255.     register char    *s, c;
  256.     register int    pathc;        /* the length of the path vector */
  257. #ifdef __GNUC__
  258.     char    **v, **pathv;
  259. #else
  260.     char    **v, **pathv, *malloc();
  261. #endif
  262.  
  263.     for (s = path, pathc = 2; c = *s++; )
  264.         if (c == DIRSEP)
  265.             ++pathc;
  266.  
  267.     if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
  268.         perror("malloc");
  269.         exit(1);
  270.     }
  271.  
  272.     for (s = path, v = pathv; (c = *s) != '\0'; ) {
  273.         if (c == DIRSEP) {
  274.             /*
  275.              * This colon is spurious.  According to some
  276.              * dubious convention it is made equivalent to a dot.
  277.              */
  278.             *v++ = ".";
  279.             if (*++s == '\0')
  280.                 *v++ = ".";
  281.                 /*
  282.                  * The PATH ended in a spurious colon.
  283.                  * To be consistent we add another dot
  284.                  * to the path vector.  One day you'll
  285.                  * be glad we did.
  286.                  */
  287.         } else {
  288.             *v++ = s;
  289.             while ((c = *++s) != '\0')
  290.                 if (c == DIRSEP) {
  291.                     *s++ = '\0';
  292.                     if (*s == '\0')
  293.                         *v++ = ".";
  294.                         /*
  295.                          * The PATH ended in a
  296.                          * (spurious) colon, so
  297.                          * add dot to the vector.
  298.                          */
  299.                     break;
  300.                 }
  301.         }
  302.     }
  303.  
  304.     *v = 0;        /* Signal the end of the path vector. */
  305.  
  306.     return pathv;
  307. }
  308.